/**
 * AJAX.OOP JavaScript Framework Core Library 
 * Home page, downoads and documentation at http://ajaxoop.org/
 * 
 * This source code is compatible with Javascript Compressor
 * http://javascriptcompressor.com/
 * You can use it to minimize code weight and reduce traffic
 * amount on your website.
 * 
 * Version 1.0.5-trunk
 * 
 * Copyright (c) 2008 Mykhailo Stadnyk <mikhus@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
var $d, $D; $d = $D = document;
var $b, $B; $b = $B = document.body;
var $n, $N; $n = $N = navigator;

$n.ua = $N.ua = $n.userAgent.toLowerCase();

// if function $ already defined - write it to _$ holder
if ($) var _$ = $;
var $ = function( id) {
	if (arguments.length > 1) {
		for (var i = 0, els = [], length = arguments.length; i < length; i++) {
			els.push( $( arguments[i]));
		}
		return els;
	}
	if (Ajax.isElement( id)) return id;
	return $d.getElementById( id);
};

if (!$$) { var $$ = function( name) {
	if (arguments.length > 1) {
		for (var i = 0, els = [], length = arguments.length; i < length; i++) {
			els.concat( $( arguments[i]));
		}
		return els;
	}
	var els = $d.getElementsByTagName( name);
	return els;
};};

if (!$A) { var $a, $A; $a = $A = function( obj) {
	if (!obj) return [];
	if (obj.toArray) return obj.toArray();
	var length = obj.length;
	var results = new Array( length);
	while (length--) results[length] = obj[length];
	return results;
};} else { var $a = $A; };

if (!$w) { var $w, $W; $w = $W = function( string) {
	if (typeof( string) != 'string') return [];
	string = string.trim();
	return string ? string.split(/\s+/) : [];
};} else { var $W = $w; };

String.prototype.has = function( ptrn) { return (this.indexOf( ptrn) > -1); };
Array.prototype.inArray = function( val) {
	for (var i = 0; i < this.length; i++)
		if (this[i] == val) return true;
	return false;
};
Array.prototype.uniq = function() {
	var result = [];
	for (var i = 0; i < this.length; i++)
		if (!result.inArray( this[i])) result[result.length] = this[i]; 
	return result;
};
Object.$extensions = ['$super','$_super','$_self'];

$n.parse = function() {
	_m = { 
		opera     : [/Opera/, /^.*?Opera\s+|\/(\d+(\.\d+)*).*?$/],
		chrome    : [/Chrome\//, /Chrome\/(.*?)(\s|$)/],
		konqueror : [/Konqueror/, /^.*?Konqueror\/(\d+(\.\d+)*).*?$/],
		firefox   : [/Firefox/, /^.*?Firefox\/(\d+(\.\d+)*).*?$/],
		mozilla   : [/Gecko/, /^.*?rv:(\d+(\.\d+)*).*?$/],
		ie        : [/MSIE/, /^.*?MSIE\s+(\d+(\.\d+)*).*?$/],
		netscape  : [/Mozilla\/\d.\d+\s+[\w\w]/, /^Mozilla\/(\d.\d+)\s+[\w\w].*?$/],
		safari    : [/Safari\/webkit|khtml/, /Safari\/(.*?)(\s|$)/]
	};
	var got = false;
	Ajax.each( _m, function( b) {
		var test = _m[b][0].test( $n.userAgent);
		if (!got && test) {
			test = true;
			Ajax.browser.version = $n.userAgent.match( _m[b][1])[1];
			Ajax.browser.app = b.ucFirst();
		} else test = false;
		Ajax.browser[b] = test;
		if (test && !got) got = true;
	});
};

/**
 * Core object Ajax - namespace for the most classes in this library
 */
var Ajax = {
	Version        : '1.0.5',
	Vendor         : 'AJAX.OOP',

	connections    : 0,
	debug          : false, // turn it on whenever you need to debug your functionality

	browser : { // Detecting known browser (most browsers will be detected with $n.parse later)
		version : '',
		app     : 'Unknown'
	},
	
	htmlEngine : { // detecting known HTML Layout Engines:
		version : ($n.ua.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
		gecko   : $n.ua.has( "gecko") && !$n.ua.has( "khtml"),
		webkit  : $n.ua.has( 'applewebkit/'),
		khtml   : !$n.ua.has( "khtml"),
		msie    : $n.ua.has( "msie")
	},

	isStrict       : $d.compatMode == "CSS1Compat",
	isSecure       : window.location.href.toLowerCase().indexOf( "https") === 0,

	hasXPath       : !!$d.evaluate, 
	hasElementExt  : !!window.HTMLElement,

	osWindows      : ($n.ua.has( "windows") || $n.ua.has( "win32")),
	osMac          : ($n.ua.has( "macintosh") || $n.ua.has( "mac os x")),
	osLinux        : ($n.ua.has( "linux")),

	extend : function( dest, src, ext) {
		var ext = ext || true;
		for (var i in src) {
			dest[i] = src[i];
			if (ext) Object.$extensions.push( i);
		}
		if (ext) Object.$extensions = Object.$extensions.uniq();
		return dest;
	},

	/**
	 * Try to resolve conflicts with $ function by using this method
	 */
	resolve : function() {
		if ($.vendor && $.vendor == Ajax.Vendor) 
			return true;
		if (_$.vendor && _$.vendor == Ajax.Vendor) { 
			var _tmp = $; $ = _$; _$ = _tmp; 
			return true;
		}
		if (Ajax.debug) {
			alert( 'Error: Native AJAX.OOP function $ could not be found!');
		}
		return false;
	},

	/**
	 * Toggle $ function between vendors
	 */
	toggle : function() {
		if (_$) {
			var _tmp = $; $ = _$; _$ = _tmp;
			return true;
		}
		return false
	},

	toJson : function( obj) {
		try {
			if (obj.toJson) return obj.toJson();
			var type = typeof obj;
			switch (type) {
				case 'undefined': case 'function': case 'unknown': return;
				case 'number' : case 'boolean': return obj.toString();
			}
			if (Ajax.isNull( obj)) return 'null';
			if (obj instanceof Date) {
				return '"' + obj.getUTCFullYear() + '-' +
					(obj.getUTCMonth() + 1).toPaddedString(2) + '-' +
					obj.getUTCDate().toPaddedString(2) + 'T' +
					obj.getUTCHours().toPaddedString(2) + ':' +
					obj.getUTCMinutes().toPaddedString(2) + ':' +
					obj.getUTCSeconds().toPaddedString(2) + 'Z"';
			}
			if (Ajax.isElement( obj)) return;
			var results = [];
			for (var property in obj) {
				var value = Ajax.toJson( obj[property]);
				if (!Ajax.isUndefined( value)) {
					results.push( Ajax.toJson( property) + ': ' + value);
				}
			}
			return '{' + results.join(', ') + '}';
		} catch (err) {
			if (Ajax.debug) alert( 'Ajax::toJson() has caught an exception: ' + err);
		}
	},

	each : function( obj, callback, clean) {
		var args = $a( arguments);
		if (Ajax.isObject( obj)) {
			for (var i in obj) {
				if (clean || !Object.$extensions.inArray( i)) callback( i);
			}
		} else if (Ajax.isArray( obj)) {
			for (var i = 0, len = obj.length; i < len; i++) 
				callback( i);
		}
	},

	clone : function( obj) {
		try {
			if (Ajax.isObject( obj)) {
				return Ajax.extend( {}, obj);
			} else if (Ajax.isArray( obj)) {
				var result = [];
				for (var i = 0; i < obj.length; i++) {
					result[i] = obj[i];
				}
				return result;
			} else {
				return obj;
			}
		} catch (err) {
			if (Ajax.debug) alert( 'Ajax::clone() has caught an exception: ' + err);
			return obj;
		}
	},

	toQs : function( obj) {
		if (Ajax.isString( obj)) return obj;
		var result = '';
		try {
			for (var key in obj) {
				var val = obj[key];
				if (Ajax.isSimple( val)) {
					result +=  ((result ? '&' : '') + key + '=' + new String( val)); 
				}
			}
		} catch (err) {
			if (Ajax.debug) alert( 'Ajax::toQs() has caught an exception: ' + err);
		};
		return result;
	},

	/**
	 * Working with types
	 */
	isElement   : function( obj) { return (obj && obj.nodeType && obj.nodeType == 1) ? true : false; },
	isArray     : function( obj) { return (obj && obj.constructor === Array); },
	isFunction  : function( obj) { return (obj && obj.constructor === Function); },
	isRegExp    : function( obj) { return (obj && obj.constructor === RegExp); },
	isString    : function( obj) { return (typeof obj == 'string'); },
	isNumber    : function( obj) { return (typeof obj == 'number'); },
	isBoolean   : function( obj) { return (typeof obj == 'boolean'); },
	isObject    : function( obj) { return (obj && !(Ajax.isArray( obj) || Ajax.isFunction( obj) || Ajax.isSimple( obj))); },
	isNull      : function( obj) { return (obj === null); },
	isUndefined : function( obj) { return (obj === 'undefined' || obj === undefined || obj === 'unknown'); },
	isSimple    : function( obj) { return (Ajax.isString( obj) || Ajax.isNumber( obj) || Ajax.isBoolean( obj) || Ajax.isRegExp( obj)); }
};

$.vendor = Ajax.Vendor;

/**
 * OOP implementation: classes definition, inheritance, polymorphism
 */
Ajax.Class = function() {
	/**
	 * Parsing passed arguments, defining variables
	 */
	var _args = $a( arguments),
		parent = (_args.length > 1 ? _args.shift() : null),
		declaration = _args.shift() || {},
		constructor = 'constructor';
	/**
	 * Check if passed arguments are valid
	 */
	if (parent && !Ajax.isFunction( parent)) {
		throw new TypeError( 'in class definition - first argument is not a parent class constructor!');
	}
	if (declaration && (!Ajax.isObject( declaration) || declaration == window || declaration == $d || declaration == $b || Ajax.isElement( declaration))) {
		throw new TypeError( 'in class definition - ' + (_args.length > 1 ? 'second' : 'passed') + ' argument is not a class declaration object!');
	}
	/**
	 * Dynamically creating constructor for class
	 */
	var _class = function() {
		this[constructor].apply( this, $a( arguments));
	};
	/**
	 * Inherit all parent properties
	 */
	if (parent) { 
		var _parent = Function.blank;
		_parent.prototype = parent.prototype;
		_class.prototype  = new _parent;
	}
	/**
	 * Writing class definition (polymorphism icluded)
	 */
	if (declaration) {
		for (var property in declaration) {
			_class.prototype[property] = declaration[property];
		}
		// line below is to fix bug with constructors in IE
		_class.prototype[constructor] = declaration[constructor] || Function.blank;
	}
	/**
	 * Defining special accessors-properties, which can be obtained in classes declaration
	 * as this.$super, this.$_super and this.$_self get access to manipulating with
	 * parent class its methods and properties
	 */
	_class.prototype.$super  = parent ? parent.prototype : Function.blank.prototype;
	_class.prototype.$_super = parent ? parent : Function.blank;
	_class.prototype.$_self  = _class;
	/**
	 * Returns dynamically created constructor
	 */
	return _class;
};

if( _$) Ajax.extend( $, _$);

Ajax.extend( Function.prototype, {
	blank : function() {},

	bind : function() {
		if (arguments.length < 2 && Ajax.isUndefined( arguments[0])) return this;
		var f = this, args = $a( arguments), object = args.shift();
		return function() { return f.apply( object, args.concat( $a( arguments))); };
	}
}, true);

Ajax.extend( RegExp.prototype, {
	match  : function() { return this.test.apply( this, $a( arguments)); },
	escape : function( str) { return String( str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); }
}, true);

Ajax.extend( String.prototype, {
	toJson : function() { return ('"' + this + '"'); },

	isJson : function() {
		var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
		return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
	},

	evalJson : function() {
		if (this.isJson()) return eval( '(' + this + ')');
		return '';
	},

	ucFirst : function () {
		return this.substr( 0, 1).toUpperCase() + this.substr( 1, this.length);
	},

	qsHash : function( separator) {
		var hash = {};
		var match = this.trim().match(/([^?#]*)(#.*)?$/);
		if (!match) return { };
		var pair = match[1].split( separator || '&');
		for (var i = 0; i < pair.length; i++) {
			var param = pair[i].split( '=');
			if (param.length == 2) {
				hash[param[0]] = param[1];
			}
		}
		return hash;
	},

	trim : function() { return this.replace( /(^\s+|\s+$)/g, ''); },
	strip : function() { return this.replace( /<.*?>/g, ''); },
	toArray : function() { return this.split(''); },
	qw : $w
}, true);

$n.parse(); delete $n.parse;

RegExp  .prototype.toJson = 
Boolean .prototype.toJson = 
Number  .prototype.toJson = 
String  .prototype.toJson ;

Ajax.extend( Array.prototype, {
	revoke : function( value) {
    	var result = [];
    	for (var i = 0; i < this.length; i++) {
        	if (this[i] != value) {
            	result[result.length] = this[i];
        	}
    	}
    	return result;
	},
	
	toJson : function() {
		var results = [];
		for (var i = 0; i < this.length; i++) {
			results[i] = Ajax.toJson( this[i]);
		}
		return '[' + results.join(', ') + ']';
	},

	first : function() { return this[0]; },
	last : function() { return this[this.length]; },
	clear : function() { this.length = 0; return this; }
}, true);

/**
 * Compatibility methods {{{
 */
_ps = String.prototype; Ajax.extend( String.prototype, { toJSON : _ps.toJson, isJSON : _ps.isJson, evalJSON : _ps.evalJson }, true); delete _ps;
_pa = Array.prototype; Ajax.extend( Array.prototype, { toJSON: _pa.toJson }, true); delete _pa;
/**
 * }}}
 */

/**
 * Ajax transport object types
 */
AJAX_TRANSPORT_TYPE_XHR    = 0;
AJAX_TRANSPORT_TYPE_SCRIPT = 1;

/**
 * Emulating XHR (XmlHttpRequest) object.
 * Actually this class is interface wrapper to XHR or other objects,
 * which are used as transport gateways for handling AJAX requests
 */
Ajax.Transport = Ajax.class({

	/**
	 * @access private
	 */
	_transport      : null,
	_availableTypes : ['xhr', 'script'],
	_type           : AJAX_TRANSPORT_TYPE_XHR,
	_connId         : 0,
	_head           : null,
	_callbackName   : '_ajaxHttpRequest',
	_currName       : '',

	_update : function() {
		var t = this._transport;
		for (var i in t) {
			try { 
				if ( !Ajax.isFunction( t[i]) 
					&&i != 'onreadystatechange' //<- specially for Firefox :(
				) this[i] = t[i];
			} catch( e) { continue; }
		}
		this.onreadystatechange.apply( this, $a( arguments));
	},

	_createCallback : function( scope) {
		var t = this;
		var scope = scope || window;
		scope[this.getCallbackName()] = function( responseText) { t.responseText = responseText; }
	},

	/**
	 * @access public but read-only
	 */
	readyState   : -1,
	responseText : '',
	responseXML  : '',
	status       : 0,
	statusText   : '',

	/**
	 * public methods
	 */
	open : function( method, url, asynchronous, login, password, callback, scope) {
		if (!this._transport) return;
		this._connId = ++Ajax.connections;
		this._currName = this._callbackName + this._connId;
		if (!this._transport.open) {
			this._createCallback( scope);
			this._transport.setAttribute( 'src', url + (url.has( '?') ? '&' : '?') + callback + '=' + this.getCallbackName() + '&' + Math.random());
			this._transport.setAttribute( 'id', this._connId);
		} else {
			this._transport.open( method, url, asynchronous, login, password);
		}
	},
	
	send : function( postBody) {
		if (!this._transport) return;
		var body = postBody || null;
		if (!this._transport.send) {
			this.head.appendChild( this._transport);
		} else {
			this._transport.send( body);
		}
	},

	abort : function() {
		if (!this._transport) return;
		if (!this._transport.abort) this._transport.abort = Function.blank;
		this._transport.abort.apply( this._transport, $a( arguments));
	},

	setRequestHeader : function( name, value) {
		if (!this._transport) return;
		if (!this._transport.setRequestHeader) this._transport.setRequestHeader = Function.blank;
		this._transport.setRequestHeader( name, value);
	},

	getAllResponseHeaders : function() {
		if (!this._transport) return;
		if (!this._transport.getAllResponseHeaders) this._transport.getAllResponseHeaders = Function.blank;
		return this._transport.getAllResponseHeaders();
	},

	getResponseHeader : function( name) {
		if (!this._transport) return;
		if (!this._transport.getResponseHeader) this._transport.getResponseHeader = Function.blank;
		return this._transport.getResponseHeader( name);
	},

	/**
	 * Default ready state change event handler
	 */
	onreadystatechange : Function.blank,

	/**
	 * Class constructor
	 */
	constructor : function( type) {
		if (type == AJAX_TRANSPORT_TYPE_XHR || type == AJAX_TRANSPORT_TYPE_SCRIPT) {
			this._type = type;
		}
		if (this._type == AJAX_TRANSPORT_TYPE_XHR) {
			try {
				this._transport = (new XMLHttpRequest() || new ActiveXObject('Msxml2.XMLHTTP') || new ActiveXObject('Microsoft.XMLHTTP') || null);
				this._transport.onreadystatechange = this._update.bind( this);
				this.readyState = 0;
			} catch( err) {
				if (Ajax.debug) alert( 'Ajax.Transport::constructor(): Cannot instantiate XHR Object. Exception caught: ' + err);
				this._transport = null;
			}
		} else if (this._type == AJAX_TRANSPORT_TYPE_SCRIPT) {
			var s = $d.createElement( 'script'); s.setAttribute( 'type', 'text/javascript');
			this._transport = s;
			this.head = $$('head')[0];
			this._currName = this._callbackName + this._connId;
			this._transport.onreadystatechange = this._transport.onload = this._update.bind( this);
		}
	},

	/**
	 * Extended functionality - public methods
	 */
	getType : function() { return this._type; },
	getAvailableTypes : function() { return this._availableTypes; },

	allow : function() {
		var args = $a( arguments), param = args.shift(), value = args.shift();
		switch (param) {
			case 'method': { return ((this._type == AJAX_TRANSPORT_TYPE_SCRIPT && value && value != 'get') ? false : true); }
			case 'status': case 'headers': case 'body' : { return ((this._type == AJAX_TRANSPORT_TYPE_SCRIPT) ? false : true); }
		}
		return true; 
	},

	getCallbackName : function() { return this._currName; },
	getTransport : function() { return this._transport; }
});

/**
 * Ajax.Options - base class for sharing options between requests
 */
Ajax.Options = Ajax.class({

	method         : 'post',
	asynchronous   : true,
	contentType    : 'application/x-www-form-urlencoded',
	encoding       : 'UTF-8',
	parameters     : '',
	postBody       : null,
	requestHeaders : {},
	evalJson       : true,
	evalJs         : true,
	crossdomain    : false,
	events         : null,
	login          : null,
	password       : null,
	callback       : 'callback',

	/**
	 * class constructor
	 */
	constructor : function( options) {
		var set = false;
		this.events = new Ajax.Events();
		if (Ajax.isObject( options) && !Ajax.isElement( options)) {
			var obj = this;
			Ajax.each( options, function( i) {
				if (!(Ajax.isUndefined( obj[i]) || Ajax.isFunction( obj[i]))) {
					obj[i] = options[i];
				}
				/**
				 * Bind passed event handlers to options class
				 */
				if (/^on[A-Z0-9]/.test( i) && Ajax.isFunction( options[i])) {
					obj.events.add( i, options[i]);
				}
			});
		}
	}
});

/**
 * Ajax.Events - base object for manipulation with events
 */
Ajax.Events = Ajax.class({

	/**
	 * @access private
	 */
	_events : null,

	/**
	 * Class constructor
	 */
	constructor : function() {
		this._events = {};
	},

	/**
	 * Adds new event to a list of known events
	 * 
	 * @access public
	 * @param String name [required] - event handler name
	 * @param Function handler [required] - event handler
	 */
	add : function( name, handler) {
		if (!this._events[name]) {
			this._events[name] = handler;
		}
	},

	/**
	 * Returns event by name if registered otherwise returns emty function
	 * 
	 * @access public
	 * @param  String name [required] - event handler name
	 * @return Function - event handler
	 */
	get : function( name) {
		if (this.registered( name))
			return this._events[name];
		return Function.blank;
	},

	/**
	 * Remove event handler by name from known events
	 *
	 * @access public
	 * @param  String name [required] - event handler name
	 * @return void
	 */
	remove : function( name) {
		this._events[name] = undefined;
	},

	/**
	 * Checks if even with name already registered
	 * 
	 * @access public
	 * @param  String name [required] - event handler name
	 * @return Boolean
	 */
	registered : function( name) {
		return (this._events[name] ? true : false);
	},

	/**
	 * Fires event with given name if such event has been registered
	 * and applying all passed arguments as well
	 *
	 * @access public
	 * @param String name  [required] - event handler name
	 * @param [Mixed, ...] [optional] - other arguments to the handler
	 * @return void
	 */
	fire : function( name) {
		var args = $a( arguments);
		args.shift();
		if (this.registered( name)) {
			try {
				this._events[name].apply( this, args);
			} catch (e) {
				if (Ajax.debug) alert( 'Ajax.Events::fire() has caught an exception: ' + err);
			};
		}
	}
});

/**
 * AJAX requests handling functionality 
 */
Ajax.Request = Ajax.class( Ajax.Options, {

	url       : '',
	callback  : 'callback',
	scope     : window,
	transport : null,
	body      : '',

	/**
	 * Class constructor.
	 *
	 * @param String url - required
	 * @param Object options - optional
	 * @param String type - optional
	 * @param String callback - optional
	 * @param Object scope - optional
	 */
	constructor : function( url, options, type, callback, scope) {
		this.$super.constructor( options);
		this.url = url;
		this.callback = Ajax.isString( callback) ? callback : this.callback;
		this.scope = (Ajax.isObject( scope) || Ajax.isElement( scope)) ? scope : this.scope;
		this.transport = new Ajax.Transport( type);
		if (type == AJAX_TRANSPORT_TYPE_SCRIPT) {
			this.transport.getTransport().charset = this.encoding;
		}
		this._request();
	},

	/**
	 * @access private
	 */
	_request : function() {
		try {
			/**
			 * Prepere request data
			 */
			if (!['get', 'post'].inArray( this.method.toLowerCase())) {
				this.parameters['_method'] = this.method;
				this.method = (this.transport.allow( 'method', 'post') ? 'post' : 'get');
			}
			var params = Ajax.toQs( this.parameters);
			if (params) {
				if (this.method && this.method.toLowerCase() == 'get') {
					this.url += ((this.url.has( '?') ? '&' : '?') + params);
				} else if (/konqueror|safari|khtml/.test( $n.ua)) {
					params += '&_=';
				}
			}
			if (this.transport.allow( 'body')) {
				this.body = (this.method == 'post' ? (this.postBody || params) : null);
			}
			/**
			 * Dispatch onCreate event
			 */
			this.events.fire( 'onCreate', this);
			/**
			 * Create connection
			 */
			this.transport.open( this.method.toUpperCase(), this.url, this.asynchronous, this.login, this.password, this.callback, this.scope);
			this.transport.onreadystatechange = this._onStateChange.bind( this);
			/**
			 * Apply request headers
			 */
			if (this.transport.allow( 'headers')) {
				this._applyHeaders();
			}
			/**
			 * Send request
			 */
			this.transport.send( this.body);
			if (!this.asynchronous && this.transport.getTransport().overrideMimeType) {
        		this._onStateChange();
        	}
		} catch (e) {
			if (Ajax.debug) alert( 'Ajax.Request::_request() has caught an exception: ' + err);
			this.events.fire( 'onException', this, e);
		}
	},

	_onStateChange : function() {
		var t = this.transport, _readyState = (t.readyState != -1 ? t.readyState : 4),
			_state = Ajax.Request.States[_readyState],
			_status = t.status || 0;
		if (t.getType() == AJAX_TRANSPORT_TYPE_SCRIPT && Ajax.isString( _readyState)) {
			_state = _readyState == 'loaded' ? 'Complete' : _readyState.ucFirst();
		} 
		if (_state == 'Complete') {
			if (t.allow( 'status')) {
				/**
				 * Normal XHR object:
				 */
				var s = _status; s = (s == 200 ? 'Success' : 'Failure');
				this.events.fire( 'on' + (this.events.registered( 'on' + _status) ? _status : s), t);
			} else {
				/**
				 * Something else:
				 */
				this.events.fire( (this.events.registered( 'on200') ? 'on200' : 'onSuccess'), t);
			}
		}
		this.events.fire( 'on' + _state, t);
		if (_state == 'Complete') {
			t.onreadystatechange = Function.blank;
			if (t.getType() == AJAX_TRANSPORT_TYPE_SCRIPT) t.head.removeChild( t.getTransport());
			this.transport = t = null;
		}
	},

	_applyHeaders : function() {
		var headers = {
			'X-Requested-With': 'XMLHttpRequest',
			'X-Powered-By' : 'AJAX.OOP/' + Ajax.Version,
			'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
		};
		if (this.method == 'post') {
			headers['Content-type'] = this.contentType + (this.encoding ? '; charset=' + this.encoding : '');
			if (this.transport.overrideMimeType && ($n.ua.match(/gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
				headers['Connection'] = 'close';
			}
		}
		if (Ajax.isObject( this.requestHeaders)) {
			Ajax.extend( headers, this.requestHeaders);
		}
		for (var name in headers) {
			if (Ajax.isString( headers[name])) {
				this.transport.setRequestHeader( name, headers[name]);
			}
		}
	}
});

Ajax.Request.States = ['Unitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

var Element = function( tag, attr) {
	if (Ajax.isIe && attr.name) {
		tag = '<' + tag + ' name="' + attr.name + '">';
		delete attr.name;
	}
	var el = $d.createElement( tag);
	if (Ajax.isObject( attr)) {
		Ajax.each( attr, function( i) { el.setAttribute( i, attr[i]); });
	}
	return Ajax.extend( el, this);
};
